﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Diagnostics;
using Microsoft.MediaPlayer.Interop;
using BMproductions.Media.MediaPlayer.WMPPlus.Properties;

namespace BMproductions.Media.MediaPlayer.WMPPlus {
	public class WMPUIAddons: WMPMenuModule, IPluginManager, IPersistableModule {
		bool HasTagEditor {
			get { return WMPPlusCore.GetBoolProp(WMPPlusProperty.AddonsTagEditor); }
		}
		IntPtr hContextMenu {
			get { return WMPPlusCore.GetPtrProp(WMPPlusProperty.AddonsContextMenu); }
		}
		string TagEditorLabel {
			get { return WMPPlusCore.GetStrProp(WMPPlusProperty.AddonsTagEditorLabel); }
		}
		public bool DisableGroupHeaders {
			get { return Owner.Settings[WMPPlusSettings.BoolNames.DisableGroupHeaders]; }
		}
		List<PlugPropsMenuItem> items;
		WMPSubMenu menuProperties;
		WMPMenuItem playNext;
		string wmpTitle {
			get { return WMPPlusCore.GetStrProp(WMPPlusProperty.AddonsWMPTitle); }
		}
		bool hasTitle { get; set; }
		string Title {
			get { return WMPPlusCore.GetStrProp(WMPPlusProperty.AddonsTitle); }
			set { UpdateTitle(value); }
		}

		[DllImport(WMPPlusPublic.WMPPlusHookName, EntryPoint = "#601")]
		private static extern void WMPUIAddonsInitialize();
		[DllImport(WMPPlusPublic.WMPPlusHookName, EntryPoint = "#602")]
		internal static extern void WMPUIAddonsDispose();
		[DllImport(WMPPlusPublic.WMPPlusHookName, EntryPoint = "#603")]
		private static extern int PlaceWMPUIAddons(IntPtr hMenu);
		[DllImport(WMPPlusPublic.WMPPlusHookName, EntryPoint = "#604")]
		private static extern void UpdateListView(
			[MarshalAs(UnmanagedType.Bool)] bool groupHeaders);
		[DllImport(WMPPlusPublic.WMPPlusHookName, CharSet = CharSet.Auto, EntryPoint = "#605")]
		private static extern void UpdateTitle(
			[MarshalAs(UnmanagedType.LPTStr)] string title);

		public WMPUIAddons(WMPPlusPublic owner, WMPMenu menu)
			: base(owner, menu, false) {
			Init();
		}

		private class AddonsSubMenu: WMPSubMenu {
			private ICollection<PlugPropsMenuItem> items;

			public AddonsSubMenu(WMPMenu owner, ICollection<PlugPropsMenuItem> items)
				: base(owner, false) {
				this.items = items;
				Init();
			}

			public override string Text {
				get { return Resources.MenuPlugins; }
			}

			protected internal override int Place(IntPtr hMenu) {
				if ((WMPPlusCore.Hook.Libraries & ImportLibrary.OLE32) != ImportLibrary.OLE32 ||
					this.items.Count == 0)
					return -1;
				return PlaceWMPUIAddons(hMenu);
			}

			protected internal override void Invoke(IntPtr hMenu) {
				int pos = 0;
				foreach (WMPMenuItem item in this.items)
					if (item.Insert(hMenu, pos))
						pos++;
			}
		}

		private class PlugPropsMenuItem: WMPMenuItem, IComparable<PlugPropsMenuItem> {
			public PlugPropsMenuItem(WMPMenu owner, WMPPlugin plugin)
				: base(owner, false) {
				Plugin = plugin;
				Init();
			}

			public override string Text { get { return this.Plugin.Label; } }
			public WMPPlugin Plugin { get; private set; }

			int IComparable<PlugPropsMenuItem>.CompareTo(PlugPropsMenuItem other) {
				return String.Compare(Text, other.Text);
			}

			protected internal override void Invoke(IntPtr hWnd) {
				HResult hr;
				try {
					if (Plugin.Original != null) {
						hr = Plugin.Original.DisplayPropertyPage(hWnd);
					} else {
						var type = System.Type.GetTypeFromCLSID(Plugin.CLSID, true);
						var plugin = (IWMPPluginUI)Activator.CreateInstance(type);
						hr = plugin.DisplayPropertyPage(hWnd);
					}
				} catch (Exception ex) {
					Trace.WriteLine(ex.Message);
					Debug.WriteLine(ex.ToString());
					hr = HResult.E_FAIL;
				}
				if (hr != HResult.S_OK) {
					string title = WMPPlusCore.GetStrProp(WMPPlusProperty.AddonsWMPTitle);
					if (title.IsNullEmpty()) title = Text;
					MessageBox.Show(null/*hWnd*/, Resources.ErrorPluginProperties,
						title, MessageBoxButtons.OK, MessageBoxIcon.Error);
				}
			}
		}

		private class PlayNextMenuItem: WMPMenuItem {
			public PlayNextMenuItem(WMPMenu owner, IWMPCore core)
				: base(owner, false) {
				WMPCore = core;
				Init();
			}

			public override string Text { get { return "Play next"; } }
			public IWMPCore WMPCore { get; private set; }

			protected internal override void Invoke(IntPtr hWnd) {
				var playlist = WMPCore.currentPlaylist;
				if (playlist == null)
					return;
				//TODO
			}
		}

		void IPluginManager.Register(WMPPlugin plugin) {
			if (IndexOfPlugin(plugin) != -1)
				return;
			CreateItem(plugin);
			this.items.Sort();
		}

		void IPluginManager.Unregister(WMPPlugin plugin) {
			int index;
			if ((index = IndexOfPlugin(plugin)) == -1)
				return;
			DeleteItem(index);
		}

		void IPluginManager.LoadPlugin(WMPPlugin plugin) { }

		void IPluginManager.UnloadPlugin(WMPPlugin plugin) { }

		void CreateItem(WMPPlugin plugin) {
			if ((plugin.Capabilities & (int)PluginFlags.PLUGIN_FLAGS_HASPROPERTYPAGE) == 0)
				return;
			this.items.Add(new PlugPropsMenuItem(menu, plugin));
		}

		void DeleteItem(int index) {
			this.items[index].Free();
			this.items.RemoveAt(index);
		}

		int IndexOfPlugin(WMPPlugin plugin) {
			for (int k = 0; k < this.items.Count; k++)
				if (this.items[k].Plugin == plugin)
					return k;
			return -1;
		}

		void BuildTaskbarATF(bool display, bool checkPlay) {
			if (checkPlay) {
				var state = Owner.WMPCore.playState;
				display = state == WMPPlayState.wmppsPaused || state == WMPPlayState.wmppsPlaying;
			}
			display = display && Owner.Settings[WMPPlusSettings.BoolNames.CurrentMediaInTitle];
			IWMPMedia3 media = null;
			if (display && (media = Owner.WMPCore.currentMedia as IWMPMedia3) == null) {
				Title = null;
				hasTitle = false;
				return;
			}
			if (media != null) {
				Title = WMPATF.BuildTitle(media, Owner.Settings[WMPPlusSettings.StringNames.TaskbarATFString], null, "Title", null);
			} else
				Title = String.Empty;
			hasTitle = true;
		}

		public override void PlayStateChange(int state) {
			switch ((WMPPlayState)state) {
			case WMPPlayState.wmppsStopped:
			case WMPPlayState.wmppsReady:
				BuildTaskbarATF(false, false);
				break;
			case WMPPlayState.wmppsPlaying:
				BuildTaskbarATF(true, false);
				break;
			}
		}

		public override void MediaChange(object Item) {
			var media = Item as IWMPMedia;
			if (media != null && media == Owner.WMPCore.currentMedia && hasTitle)
				BuildTaskbarATF(true, false);
		}

		protected override void Init() {
			WMPUIAddonsInitialize();
			this.items = new List<PlugPropsMenuItem>();
			foreach (WMPPlugin plugin in WMPPlusCore.Plugins)
				CreateItem(plugin);
			WMPPlusCore.Plugins.AddModule(this);
			this.items.Sort();
			this.menuProperties = new AddonsSubMenu(menu, items);
			this.playNext = new PlayNextMenuItem(menu, Owner.WMPCore);
			this.hasTitle = true;
			Update();
			Owner.Settings.AddModule(this);
		}

		public override void Dispose() {
			WMPPlusCore.Plugins.RemoveModule(this);
			this.playNext.Free();
			this.playNext = null;
			while (this.items.Count > 0)
				DeleteItem(0);
			this.items.Clear();
			this.items = null;
			this.menuProperties.Free();
			this.menuProperties = null;
			Owner.Settings.RemoveModule(this);
			UpdateListView(true);
			BuildTaskbarATF(false, false);
			WMPUIAddonsDispose();
		}

		public void Update() {
			UpdateListView(!DisableGroupHeaders);
			BuildTaskbarATF(true, true);
		}
	}
}
